package base.thread_example.example03;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 *  JUC编程实现:生产者/消费者问题
 *  JDK1.5解决多线程安全性问题新方式
 */
public class ProducerAndConsumer {
    public static void main(String[] args) {
        // 创建一份待生产资源
        Resource r = new Resource("烤鸭");

        // 创建生产协议
        Producer producer = new Producer(r);
        // 创建消费协议
        Consumer consumer = new Consumer(r);

        // 创建2生产者
        new Thread(producer, "生产者-1").start();
        new Thread(producer, "生产者-2").start();
        // 创建3消费者
        new Thread(consumer, "消费者-1").start();
        new Thread(consumer, "消费者-2").start();
        new Thread(consumer, "消费者-3").start();

    }
}


class Producer implements Runnable {
    private Resource r ;
    public Producer(Resource r){
        this.r = r;
    }

    @Override
    public void run() {
        while (true){
            try {
                r.set();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Consumer implements Runnable {
    private Resource r;
    public Consumer(Resource r){
        this.r = r;
    }

    @Override
    public void run() {
        while (true){
            try {
                r.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Resource {
    private static final Logger log = LoggerFactory.getLogger(Resource.class);
    private String name;//资源名称
    private int count=1;//资源编号
    private boolean flag = false;//资源标识：一开始表示没有资源
    private static String tempName;//临时生产产品名

    public Resource(String name){
        this.name = name;
    }

    //创建一个锁对象,ReentrantLock 是 Java语言层面提供的代替操作系统层面的 Monitor 监视器对象
    Lock lock = new ReentrantLock();
    //通过已有的锁，获取该锁上的监视器对象
    Condition con = lock.newCondition();


    // 生产方法
    public void set() throws InterruptedException {
        lock.lock();
        try {
            while(this.flag){// 有资源,进入wait
                con.await();
            }
            // 生产第多少只鸭子的情况只有Resource自己知道,count在Resource内部定义
            tempName = this.name + count;
            this.flag = !this.flag;
            log.info("{} 生产了 {}", Thread.currentThread().getName(), tempName);
            count++;
            con.signalAll();
        }finally {
            lock.unlock();
        }
    }

    // 消费方法
    public void get() throws InterruptedException {
        lock.lock();
        try {
            while(!this.flag){//没有资源,进入wait,等待资源生产
                con.await();
            }
            this.flag = !this.flag;
            log.info("------------------------>{} 消费了 {}", Thread.currentThread().getName(), tempName);
            con.signalAll();
        }finally {
            lock.unlock();
        }
    }



    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
